/**
 */

#ifndef UTILS_MEM_POOL_MANAGER_H_
#define UTILS_MEM_POOL_MANAGER_H_

#include <sys/types.h>
#include <unistd.h>
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include <vector>

#include "fake_log.h"
#include "mem_allocator.h"

namespace MemTest {
class MemPoolManager {
 public:
  MemPoolManager(const std::string &in_name, int8_t *const in_addr, uint32_t in_unit_size, uint32_t in_unit_count);
  ~MemPoolManager();
  int8_t *mem_alloc(uint32_t mem_size);
  void mem_free(const int8_t *const in_addr);
  const int8_t *get_pool() const {
    return reinterpret_cast<const int8_t *>(pool_addr_);
  }
  bool is_manager_of(const int8_t *const in_addr) const {
    const uint32_t uint_offset = unit_size_ * unit_count_;
    return ((in_addr >= pool_addr_) && (in_addr < std::next(pool_addr_, static_cast<ptrdiff_t>(uint_offset))));
  }
  bool empty() const {
    return free_count_ <= 0;
  }

 private:
  std::string pool_name_;
  int8_t *pool_addr_;
  uint32_t unit_size_;
  uint32_t unit_count_;
  uint32_t free_count_;
  uint64_t alloc_call_count_;
  uint64_t return_null_count_;
  uint64_t request_too_big_;
  std::mutex pool_manager_mutex_;
  std::vector<bool> in_use_;
  std::vector<uint32_t> next_free_;
  uint32_t first_free_;
  uint32_t last_free_;
};

class MemPool {
 public:
  // support sys malloc
  MemPool(const std::string &in_name, uint32_t in_unit_sz, uint32_t in_unit_nm, uint64_t in_alignment,
          bool in_is_sys_malloc = false);

  ~MemPool();
  int8_t *mem_alloc() const;
  void mem_free(const int8_t *const in_addr) const;

  /**
   * @brief : is_manager_of
   * @param  address_p  :   Address Pointer
   * @return true  : Is pool pointer
   * @return false; : Not pool pointer
   */
  bool is_manager_of(const int8_t *const address_p) const {
    return pool_manager_ptr_->is_manager_of(address_p);
  }

  bool empty() const {
    return pool_manager_ptr_->empty();
  }
  int8_t *get_aligned_address(const int8_t *const in_address, uint64_t in_alignment_size);

 private:
  std::string pool_name_;
  int8_t *pool_addr_;
  int8_t *aligned_pool_;
  uint32_t unit_size_;
  uint32_t unit_count_;
  uint64_t alignment_size_;
  std::shared_ptr<MemPoolManager> pool_manager_ptr_;
  std::shared_ptr<MemAllocDelegate> alloc_delegate_;
  // support the sys malloc
  bool is_sys_malloc_ = false;
};

}  // namespace MemTest
#endif  // UTILS_MEM_POOL_MANAGER_H_
